#ifndef RS_STREAM_H
#define RS_STREAM_H

#include <string>
#include <stdio.h>
#include "rs_types.h"
#include "rs_string.h"
using namespace std;

enum rs_encoding {
    rse_autodetect,
    rse_ascii,
    rse_utf8,
    rse_utf16, // utf16LE
};


enum rs_eol {
    rse_crlf,
    rse_lf,
    rse_cr,
};

class rs_istream {
    // can seek using 64-bit offsets
    // encoding support for: binary or utf-16
public:
    rs_istream () {
        f = 0;
        m_file_enc = rse_autodetect;
    }
    rs_istream (const rs_string& fname, rs_encoding encoding=rse_autodetect) {
        open (stringed(fname), encoding);
    }
    rs_istream (const string& fname, rs_encoding encoding=rse_autodetect) {
        open (fname, encoding);
    }
    void open (const rs_string& fname, rs_encoding encoding=rse_autodetect, bool report_failure=true);
    void open (const string& fname, rs_encoding encoding=rse_autodetect) {
        open (rs_stringed(fname), encoding);
    }
    ~rs_istream () {if (f) fclose(f); f=NULL; }
    bool seek (int64 pos, int origin);
    int64 get_pos (void);
    int64 file_size (void) { return m_file_size;};
    bool eof(void)  {return get_pos() == m_file_size;};
    bool read (char *buffer, size_t read_amount);
    bool good(void) { return f!=0;};
    bool read_line (wstring& line, bool cr_ordinary=false);
    bool read_line (wchar_t *line, size_t buf_size_chars, bool cr_ordinary=false);
    bool read_line (char *line, size_t buf_size_chars, bool cr_ordinary=false);
    bool read_file (wstring& text);
    bool read_file_bytes (string& bytes);
    rs_encoding get_encoding () { return m_file_enc; };

private:
    FILE *f;
    rs_encoding m_file_enc;
    int64 m_file_size;
    bool check_unicode_signature (const char *signature, rs_encoding encoding);
};


class rs_ostream {
    // encoding support for: binary or utf-16
public:
    rs_ostream (const rs_string& fname, rs_encoding encoding=rse_utf8) {
        init (fname, encoding);
    }
    rs_ostream (const string& fname, rs_encoding encoding=rse_utf8) {
        init (rs_stringed(fname), encoding);
    }
    ~rs_ostream () { close(); };
    void close () {if (f) fclose(f); f=NULL; };
    bool write (const void* data, int length=-1);
    void write_line (const wstring& line, bool append_endl=true);
    bool good(void) { return f!=0;};
    bool is_open(void) { return f!=0;};
    void flush();
private:
    void init (const rs_string& fname, rs_encoding encoding=rse_utf8);
    FILE *f;
    rs_encoding file_enc;
};

bool compare_text_files (const rs_string& fname1, const rs_string& fname2);
inline bool file_exists (const rs_string& fname) {
    rs_istream ifs;
    ifs.open (fname, rse_autodetect, false);
    return ifs.good();
}
#endif
